package net.madarco.phpsense;

import net.madarco.phpsense.util.EclipseConsole;
import net.madarco.phpsense.util.InferenceUtil;
import net.madarco.phpsense.util.Logger;
import net.madarco.phpsense.util.QuercusEnviroment;

import org.eclipse.dltk.ast.ASTNode;
import org.eclipse.dltk.ast.expressions.CallExpression;
import org.eclipse.dltk.ast.references.SimpleReference;
import org.eclipse.dltk.ast.references.VariableReference;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.ti.IGoalEvaluatorFactory;
import org.eclipse.dltk.ti.goals.ExpressionTypeGoal;
import org.eclipse.dltk.ti.goals.GoalEvaluator;
import org.eclipse.dltk.ti.goals.IGoal;
import org.eclipse.php.internal.core.codeassist.CodeAssistUtils;
import org.eclipse.php.internal.core.compiler.ast.nodes.PHPCallExpression;
import org.eclipse.php.internal.core.compiler.ast.nodes.StaticMethodInvocation;
import org.eclipse.php.internal.core.typeinference.goals.MethodElementReturnTypeGoal;

public class GoalEvaluatorFactory implements IGoalEvaluatorFactory {
	private static final Logger log = new Logger();
	
	private static EclipseConsole console = new EclipseConsole();

	private QuercusEnviroment quercusUtil;

	public GoalEvaluatorFactory() {
		quercusUtil = new QuercusEnviroment("phpSense.php", console, true);

		console.trace("PhpSense GoalEvaluatorFactory started");
	}
	
	public GoalEvaluator createEvaluator(IGoal goal) {
		
		Class goalClass = goal.getClass();
		
		if(log.isDebug()) {
			System.out.println("Goal class: " + goalClass);
		}
			
		// We're overriding only the expression type goal:
		if (goalClass == ExpressionTypeGoal.class) {
			ExpressionTypeGoal expressionTypeGoal = (ExpressionTypeGoal) goal;
			ASTNode expression = expressionTypeGoal.getExpression();
			
			if(log.isDebug()) {
				System.out.println("ExpressionTypeGoal expression class: " + expression.getClass());
			}

			// Check the expression AST node type
			if (this.quercusUtil.isFindExpressionStaticMethodCallTypeDefined() && expression instanceof StaticMethodInvocation) {
				CallExpression inv = (CallExpression) expression;
				ASTNode receiver = inv.getReceiver();
				
				//The receiver should only be a class (SimpleReference)
				if (receiver instanceof SimpleReference) {
					String rcvClassName = ((SimpleReference) receiver).getName();

					String className = this.quercusUtil.callFindExpressionStaticMethodCallType(
									rcvClassName, inv.getCallName().getName(),
									inv.getArgs().getChilds());
					
					if(!className.isEmpty()) {				
							return new TypeNameGoalEvaluator(goal, className);
					}
				}
			}
			else if (this.quercusUtil.isFindExpressionMethodCallTypeDefined() && expression instanceof PHPCallExpression) {
				CallExpression inv = (CallExpression) expression;
				ASTNode receiver = inv.getReceiver();

				if (receiver instanceof VariableReference ) {
					VariableReference rcvRefVariable = ((VariableReference) receiver);
					ISourceModule sourceModel = InferenceUtil.getSourceModel(expressionTypeGoal);
					IType[] receiverType = CodeAssistUtils.getVariableType(sourceModel, rcvRefVariable.getName(), rcvRefVariable.sourceStart());

					String className = this.quercusUtil.callFindExpressionMethodCallType(
									receiverType, inv.getCallName().getName(),
									inv.getArgs().getChilds());

					if(!className.isEmpty()) {				
							return new TypeNameGoalEvaluator(goal, className);
					}
				}
			}
		}
		else if(goalClass == MethodElementReturnTypeGoal.class) {
			MethodElementReturnTypeGoal returnType = (MethodElementReturnTypeGoal) goal;
			//Con ExpressionTypeGoal ho solo i nomi, 
			//qui invece ho solo i tipi (non ho i valori degli scalari), devo usare i goal evaluator e i subgoal?
			//Da Class->method(parmClasses..) estrae il valore restituito:
			
			returnType.getTypes();
		}

		// Give the control to the default PHP goal evaluator
		return null;
	}
	

}